#pragma once
#include "Socket.hpp"
#include <sys/epoll.h>

#include <thread>
#include <bitset>

class tcpServer
{
    static const uint16_t defaultPort = 2025;
    static const size_t fdnums = 1024;

public:
    tcpServer(uint16_t port = defaultPort)
        : _listensock(-1), _port(port), _epfd(-1) {}
    ~tcpServer()
    {
        if (_listensock > 0)
            close(_listensock);
        _listensock = -1;
    }

    // 初始化到监听即可
    void init()
    {
        // 服务器初始化
        std::cout << "init start" << std::endl;
        _listensock = mySocket::creatSockfd();
        mySocket::Bind(_listensock, _port);
        mySocket::Listen(_listensock, gbacklog);

        // epoll初始化

        // epoll IO多路复用并发处理多个客户端连接
        // 1.创建epollfd，注意参数无作用了，由数组->链表了
        _epfd = epoll_create(1);

        // 使用epollctl，首先添加listenfd和设置EPOLLIN
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = _listensock;
        epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock, &ev);

        std::cout << "init success _epfd" << _epfd << "  listenfd" << _listensock << std::endl;
    }

    void run()
    {
        epoll_event *revents = new struct epoll_event[fdnums];
        // epoll_event revents[fdnums];

        while (true)
        {
            // std::cout << "等待epoll事件..." << std::endl;
            int n = epoll_wait(_epfd, revents, fdnums, -1);
            // std::cout << "epoll_wait返回 " << n << " 个就绪事件" << std::endl;

            // 遍历就绪队列，epoll只会返回真的就绪的事件。不会返回无效事件，减少遍历
            for (int i = 0; i < n; i++)
            {
                // 首先要处理监听事件就绪
                int connfd = revents[i].data.fd;
                uint32_t event = revents[i].events;

                if (_listensock == connfd && (event & EPOLLIN))
                {

                    std::string clientip;
                    uint16_t clientport;
                    int clientsockfd = mySocket::Accept(_listensock, clientip, clientport);

                    // 将新事件注册到epoll关心中,注意每一个fd都要创建一个events
                    struct epoll_event ev;
                    ev.data.fd = clientsockfd;
                    ev.events = EPOLLIN;
                    epoll_ctl(_epfd, EPOLL_CTL_ADD, clientsockfd, &ev);

                    std::cout << clientip << ":" << clientport << "连接服务器,为其创建的fd为" << clientsockfd << std::endl;
                }
                else if (event & EPOLLIN)
                {
                    // 读事件
                    char buffer[128];
                    Recver(connfd, buffer, sizeof(buffer));
                    // std::cout << "收到的数据为" << buffer << std::endl;

                    Sender(connfd, buffer);
                }
                else if (event & EPOLLOUT)
                {
                    // 写事件
                }
                else
                {
                    // 其他事件
                }
            }
        }
    }

private:
    size_t Recver(int clientsock, char *buffer, size_t length)
    {
        assert(buffer != nullptr);
        memset(buffer, 0, sizeof(buffer));
        ssize_t n = recv(clientsock, buffer, length - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "recv success" << std::endl;
        }
        else if (n == 0)
        {
            std::cout << "client quit" << std::endl;

            // 先移除套接字，因为此时套接字是合法的。如果先close，套接字是非法的！可能被回收了！
            epoll_ctl(_epfd, EPOLL_CTL_DEL, clientsock, nullptr);
            close(clientsock);
        }
        else
        {
            epoll_ctl(_epfd, EPOLL_CTL_DEL, clientsock, nullptr);
            close(clientsock);
            std::cout << "recv error" << std::endl;
            return -1;
        }

        return n;
    }

    // select多路复用简易处理信息并且返回，无需循环recv并send。事件就绪我处理发送即可
    void Sender(int clientsock, char *buffer)
    {
        // std::string outbuffer = "server echo:";
        // outbuffer += buffer;
        // std::cout << "发送的信息是:" << outbuffer << std::endl;

        // // 注意数据长度不可以使用sizeof，这个长度是一个指针
        // send(clientsock, outbuffer.c_str(), strlen(outbuffer.c_str()), 0);

        int n;
        std::string body = "<h1>hello world</h1>";
        std::string outbuffer;
        outbuffer =
            "HTTP/1.1 200 OK\r\n"
            "Content-Type: text/html; charset=utf-8\r\n"
            "Content-Length: " +
            std::to_string(body.size()) + "\r\n"
                                          "Server: Apache/2.4.41\r\n"
                                          "Date: Mon, 18 Dec 2023 08:32:10 GMT\r\n"
                                          "X-Frame-Options: DENY\r\n"
                                          "X-Content-Type-Options: nosniff\r\n"
                                          "Referrer-Policy: strict-origin-when-cross-origin\r\n"
                                          "\r\n" // 空行分隔头部和正文
            + body;
        int count = send(clientsock, outbuffer.c_str(), outbuffer.size(), 0);
        if (count == 0)
        {
            epoll_ctl(_epfd, EPOLL_CTL_DEL, clientsock, nullptr);
            close(clientsock);
        }
    }

private:
    int _listensock;
    std::string _ip;
    uint16_t _port;
    int _epfd;
};